<?php
namespace App\Services\Activity;

use App\Enums\ActivityEnum;
use App\Exceptions\BasicException;
use App\Models\ActivityDB\Labour2022RewardLog;
use App\Models\MainDB\Gift;
use App\Models\MainDB\GiftBackpack;
use App\Models\MainDB\MallOrders;
use App\Models\MainDB\MallProducts;
use App\Repositories\Activity\LabourRepository;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Throwable as ThrowableAlias;

class LabourRewardService
{
    /**
     * @throws BasicException
     */
    private function beforeReceive(int $userId, int $id)
    {
        $repo = new LabourRepository();
        $tasks = $repo->task($userId);
        $reward = $tasks->where('id', $id)->first();
        if (empty($reward)) {
            throw new BasicException(51, 'Id not Found');
        }
        if ($reward->receive_status !== ActivityEnum::RECEIVE_STATUS_CAN) {
            throw new BasicException(51, '不能领奖');
        }
        return $reward;
    }

    /**
     * @throws BasicException
     */
    public function receive(int $userId, int $id): Collection
    {
        try {

            $reward = $this->beforeReceive($userId, $id);
            $rewards = (new Collection())->add($reward);

            if (!app('redis')->set("labour_receive:$userId:$id", 'lock', 'ex', 15, 'nx')) {
                throw new BasicException(52011);
            }

            $db = DB::connection('mysql');
            $activityDb = DB::connection('mysql_activity');
            $db->beginTransaction();
            $activityDb->beginTransaction();

            $rewardLog = $this->addGiftProduct($rewards, $userId);
            Labour2022RewardLog::query()->insert($rewardLog);

            $activityDb->commit();
            $db->commit();

        } catch (ThrowableAlias $exception) {
            isset($db) && $db->rollBack();
            isset($activityDb) && $activityDb->rollBack();
            $code = $exception instanceof BasicException ? $exception->getCode() : 52013;
            $msg = $exception instanceof BasicException ? $exception->getMessage() : '';

            $this->setErrLog($exception, $userId);

            throw new BasicException($code, $msg);
        }
        return $rewards;
    }

    private function addGiftProduct($rewards, int $uid)
    {
        // 礼物
        $rewards->where('reward_type', Gift::RELATION_TYPE)->each(function ($item) use ($uid, &$rewardLog) {

            $item->reward = $item->gift;
            if (! empty($item->reward)) {
                (new GiftBackpack())->addGift($uid, $item->reward->id, $item->count);
                $rewardLog[] = $this->makeRewardLogData($item, $uid);
            }

        });

        // 商品
        $rewards->where('reward_type', MallProducts::RELATION_TYPE)->each(function ($item) use ($uid, &$rewardLog) {
            $item->reward = $item->product;
            if (! empty($item->reward)) {
                (new MallOrders())->addProduct($uid, $item->reward->id, $item->count, $item->reward->category_id);
                $rewardLog[] = $this->makeRewardLogData($item, $uid);
            }
        });
        return $rewardLog;
    }


    private function makeRewardLogData($item, int $userId): array
    {
        $totalCoin = MallProducts::RELATION_TYPE === $item->reward_type ? 0 : $item->count * $item->reward->price;
        return [
            'setting_id'        => $item->setting_id,
            'reward_setting_id' => $item->id,
            'user_id'           => $userId,
            'reward_type'       => $item->reward_type,
            'reward_id'         => $item->reward_id,
            'count'             => $item->count,
            'total_coin'        => $totalCoin,
            'desc'              => ''
        ];
    }

    private function setErrLog($exception, $userId): void
    {
        if (! ($exception instanceof BasicException)) {
            Log::info(" 五一活动领奖失败: {$userId} :". $exception->getMessage());
        }
    }

}
